/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package fr.loof.fonzie.keywords;

import java.util.List;
import java.util.ListIterator;

import fr.loof.fonzie.parsers.Constraint;
import fr.loof.fonzie.parsers.DelegateProperty;
import fr.loof.fonzie.parsers.JPQLPersistenceQuery;
import fr.loof.fonzie.parsers.KeyWord;
import fr.loof.fonzie.parsers.Property;
import fr.loof.fonzie.parsers.QueryElement;

public class OfType
    extends KeyWord
    implements Constraint
{

    @Override
    public boolean postProcess( ListIterator<QueryElement> elements )
    {
        elements.remove();
        if ( !elements.hasPrevious() )
        {
            throw new IllegalStateException( keyword + " keyword must follow an entity property name" );
        }
        QueryElement e = elements.previous();
        if ( e instanceof Property )
        {
            elements.set( new TypeProperty( (Property) e ) );
        }
        return true;
    }

    @Override
    public final void process( JPQLPersistenceQuery query, List<Class> params )
    {
        Property property = query.getCurrentProperty();
        Class arg = params.remove( 0 );
        property.checkParameterType( arg );

        query.append( " = :" ).append( property.getName() );
        query.add( property.getName(), Class.class );
    }

    private class TypeProperty
        extends DelegateProperty
    {
        private TypeProperty( Property property )
        {
            super( property );
        }

        @Override
        public void process( JPQLPersistenceQuery query, List<Class> params )
        {
            query.append( " type(" )
                 .append( query.getCurrentEntityShortName() )
                 .append( "." )
                 .append( getName() )
                 .append( ")" );
            query.setCurrentProperty( this );
        }

        public boolean doCheckType( Class parameterType )
        {
            return parameterType.isAssignableFrom( Class.class );
        }

        @Override
        public String toString()
        {
            return "type(" + super.toString() + ")";
        }
    }

}